package editor;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
import java.util.Stack;
import java.util.Timer;
import java.util.TimerTask;
import java.util.regex.Pattern;

import game.Main;

import org.lwjgl.input.Mouse;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.KeyListener;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;

import components.Block;
import components.Field;
import components.Space;

/**
 * This class implements the map editor.
 * It loads the content of the files, changes it and is able to save them. 
 * It also creates new maps in three different sizes.
 *
 */
public class StartEditor extends BasicGameState implements KeyListener{


	/**
	 * This variable is true, when the user creates a map
	 */
	private boolean create; 

	/**
	 * This variable is true, when the user tries to save a map
	 */
	private boolean save;

	/**
	 * This variable is true, when the user is loading a map
	 */
	private boolean load;

	/**
	 * This variable is true, when the user types to less chars for saving
	 */
	private boolean lessChars;

	/**
	 * This variable is true, when the user works on a map
	 */
	private static boolean work;

	/**
	 * Size of the actual map
	 */
	private int size;

	/**
	 * This is the frame for crating a map
	 */
	private int sizefield;

	/**
	 * X-coordinates for the start of the drawing
	 */
	private int startx;

	/**
	 * Y-coordinates for the start of the drawing
	 */
	private int starty;

	/**
	 * X-coordinates for the start of the mini map
	 */
	private int minix;

	/**
	 * Y-coordinates for the start of the mini map
	 */
	private int miniy;

	/**
	 * This array contains all used fields
	 */
	private float[][] field;

	/**
	 * This array contains all used ground
	 */
	private float[][] ground;

	/**
	 * This array contains all starting points
	 */
	private float[][] player;

	/**
	 * Contains all Images of the different fields
	 */
	private Image[] fields;

	/**
	 * Contains all Images of the different grounds
	 */
	private Image[] grounds;

	/**
	 * Contains all Images of the different players
	 */
	private Image[] players;

	/**
	 * This is an image of an empty frame for an easy creation
	 */
	private Image frame;

	/**
	 * This variable gives information about the users selection. That means if he's working on grounds or fields etc. 
	 */
	private String mod;

	/**
	 * Number of the selected field, ground, etc.
	 */
	private int selected;

	/**
	 * Is used to handle time
	 */
	private Timer timer;

	/**
	 * Name of the actual map
	 */
	private String name;

	/**
	 * String for temporarily saving the save name
	 */
	private boolean helper=true;


	/**
	 * Standard constructor
	 * @param stat Status number of this window
	 */
	public StartEditor(int stat){

	}

	/**
	 * A modification of the keyPressed method to save the saving name
	 */
	public void keyPressed(int key, char c) {
		if(this.helper && this.name.length()<=25){    
			this.name+=c;
		}
		this.helper= !this.helper;
	}

	/**
	 * Initiation if this object. Loading pictures and initialising the variables
	 */
	public void init(GameContainer gc, StateBasedGame sbg) throws SlickException {
		this.size=0;
		this.sizefield=0;

		//Field Graphics
		this.fields = new Image[]{new Image("/Graphics/field3.png"),new Image("/Graphics/leer.png"),new Image("/Graphics/field2.jpg"),
				new Image("/Graphics/field1.jpg"),new Image("/Graphics/field4.jpg"),new Image("/Graphics/field5.png"),
				new Image("/Graphics/field6.gif"),new Image("/Graphics/field7.png"),new Image("/Graphics/field8.png"),
				new Image("/Graphics/field9.png"),new Image("/Graphics/field10.png"),new Image("/Graphics/field11.gif")};

		//Ground Graphics
		this.grounds = new Image[]{new Image("/Graphics/leer.png"),new Image("/Graphics/ground1.gif"),new Image("/Graphics/ground2.gif"),
				new Image("/Graphics/ground3.jpg"),new Image("/Graphics/ground4.jpg"),new Image("/Graphics/ground5.jpg"),
				new Image("/Graphics/ground6.jpg"),new Image("/Graphics/ground7.jpg"),new Image("/Graphics/ground8.jpg")};
		//Player Graphics
		Image sprite = new Image("/Graphics/bomberman_sprite.gif");
		this.players = new Image[]{new Image("/Graphics/leer.png"),sprite.getSubImage(106, 0, 17, 30), sprite.getSubImage(106, 54, 17, 30),
				sprite.getSubImage(106, 108, 17, 30), sprite.getSubImage(106, 162, 17, 30), sprite.getSubImage(106, 216, 17, 30)};

		frame=new Image("/Graphics/frame.png");

		this.player=new float[][]{{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
		this.mod="";
		this.selected=0;
		work=this.save=false;
		this.timer = new Timer();
		this.name="";


	}

	/**
	 * Render all graphics
	 */
	public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException {

		g.setColor(Color.darkGray);
		g.fillRect(270,0,10,game.Main.sizey);
		g.fillRect(0,255,270,10);

		g.setColor(Color.white);

		g.drawString("New", 40, 170);
		g.drawString("Load", 40, 200);
		g.drawString("Save", 40, 230);

		g.drawString("Exit", 120, 170);

		if(this.create){
			g.setColor(Color.darkGray);

			g.fillRect(game.Main.sizex/2-20,120,210,190);

			g.setColor(Color.white);
			g.drawString("Choose field zize:", game.Main.sizex/2, 130);
			g.drawString("Small", game.Main.sizex/2, 170);
			g.drawString("Medium", game.Main.sizex/2, 200);
			g.drawString("Big", game.Main.sizex/2, 230);

			if(this.sizefield>0){
				g.drawString("Create", game.Main.sizex/2, 280);
			}
		}

		if(this.sizefield>0 && !work){
			g.setColor(Color.red);
			g.drawRect(startx, starty, this.sizefield, this.sizefield);
		}

		if(this.field != null && this.ground != null && work){

			for(int i=0;i<this.ground.length;i++){
				for(int j=0;j<this.ground[i].length;j++){

					frame.draw(startx+i*30, starty+j*30,30,30);
					grounds[(int) this.ground[i][j]].draw(startx+i*30, starty+j*30,30,30);
					fields[(int) this.field[i][j]].draw(startx+i*30, starty+j*30,30,30);

					grounds[(int) this.ground[i][j]].draw(this.minix+i*7, this.miniy+j*7,7,7);
					fields[(int) this.field[i][j]].draw(this.minix+i*7, this.miniy+j*7,7,7);
				}

			}
			for(int i=0;i<this.player.length;i++){
				if(this.player[i][0]>=0 && this.player[i][1]>=0){
					this.players[i].draw(startx+this.player[i][0]*30,starty+this.player[i][1]*30, 30, 30);
				}
			}

		}

		g.setColor(Color.white);
		g.drawString("Ground", 40, 275);
		g.drawString("Indestructible", 40, 305);
		g.drawString("Fields", 40, 335);
		g.drawString("Start Positions", 40, 365);

		g.drawRect(25, 400, 220, 280);

		g.setColor(Color.red);
		if(this.mod.equals("ground")){
			g.drawString("Ground", 40, 275);

			for(int i =0; i<this.grounds.length;i++){
				grounds[i].draw(30+(i%7)*30,405+(int)(i/7)*30,30,30);
				if(i==this.selected){
					frame.draw(30+(i%7)*30,405+(int)(i/7)*30,30,30);
				}
			}
			if(work && Mouse.getX()>280){
				grounds[this.selected].draw( (float)Mouse.getX()-12.5f ,(float)Main.sizey-Mouse.getY()-12.5f ,25 ,25);
			}

		}
		else if(this.mod.equals("indes")){
			g.drawString("Indestructible", 40, 305);
			fields[0].draw(30,405,30,30);
			frame.draw(30,405,30,30);

			if(work && Mouse.getX()>280){
				fields[this.selected].draw( (float)Mouse.getX()-12.5f ,(float)Main.sizey-Mouse.getY()-12.5f ,25 ,25);
			}
		}
		else if(this.mod.equals("field")){
			g.drawString("Fields", 40, 335);
			for(int i =1; i<this.fields.length;i++){
				fields[i].draw(30+((i-1)%7)*30,405+(int)((i-1)/7)*30,30,30);
				if(i==this.selected){
					frame.draw(30+((i-1)%7)*30,405+(int)((i-1)/7)*30,30,30);
				}
			}

			if(work && Mouse.getX()>280){
				fields[this.selected].draw( (float)Mouse.getX()-12.5f ,(float)Main.sizey-Mouse.getY()-12.5f ,25 ,25);
			}
		}
		else if(this.mod.equals("starts")){
			g.drawString("Start Positions", 40, 365);

			for(int i =0; i<this.players.length;i++){

				players[i].draw(30+(i%7)*30,405+(int)(i/7)*30,30,30);
				if(i==this.selected){
					frame.draw(30+(i%7)*30,405+(int)(i/7)*30,30,30);
				}
			}

			if(work && Mouse.getX()>280){
				players[this.selected].draw( (float)Mouse.getX()-12.5f ,(float)Main.sizey-Mouse.getY()-12.5f ,25 ,25);
			}

		}

		if(this.save==true){

			g.setColor(Color.darkGray);

			g.fillRect(game.Main.sizex/2-40,120,250,190);

			g.setColor(Color.white);
			g.drawString("Type the Name (max. 25):", game.Main.sizex/2-30, 140);
			g.drawString(name, game.Main.sizex/2-30, 180);
			g.drawString("Save", game.Main.sizex/2-30, 230);
			if(this.lessChars){
				g.drawString("Type some chars", game.Main.sizex/2-30, 270);
			}

		}

		if(this.load==true){

			File f = new File("maps/");
			File[] files = f.listFiles();

			g.setColor(Color.darkGray);

			g.fillRect(game.Main.sizex/2-40,120,250, 400);

			g.setColor(Color.white);
			g.drawString("Load File:", game.Main.sizex/2-30, 140);

			for(int i=0;i<files.length;i++){
				g.drawString(files[i].getName(), game.Main.sizex/2-30, 170+i*25);
			}




		}



	}

	/**
	 * Method to update the variables and use all the input
	 */
	public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException {

		Input in = gc.getInput();
		int xpos = Mouse.getX();
		int ypos = Mouse.getY();

		if(in.isKeyDown(Input.KEY_ESCAPE)){
			sbg.enterState(0);
		}

		if((xpos>120 && xpos<150) && (ypos<Main.sizey-170 && ypos>Main.sizey-185) && in.isMouseButtonDown(0)){
			//auf exit
			sbg.enterState(0);
		}

		if((xpos>40 && xpos<65) && (ypos<Main.sizey-170 && ypos>Main.sizey-185) && in.isMouseButtonDown(0)){
			//auf new
			this.create=true;
			this.save=false;
			this.load=false;
			work=false;
		}

		if((xpos>40 && xpos<65) && (ypos<Main.sizey-200 && ypos>Main.sizey-215) && in.isMouseButtonDown(0)){
			//auf laden

			this.create=false;
			this.save=false;
			this.load=true;

		}

		if((xpos>game.Main.sizex/2-40 && xpos<game.Main.sizex/2+210) && (ypos<game.Main.sizey-120 && ypos>game.Main.sizey-520) && in.isMouseButtonDown(0) && this.load){
			//im lade kasten
			File f = new File("maps/");
			File[] files = f.listFiles();
			int number=0;
			String row;
			String[] help;
			String[][] help2;

			for(int i = 0; i<files.length; i++){
				if((xpos>game.Main.sizex/2-30 && xpos<game.Main.sizex/2+210) && (ypos<game.Main.sizey-170-i*25 && ypos>game.Main.sizey-170-i*25-15) && in.isMouseButtonDown(0)){
					number=i;
				}
			}

			try {
				BufferedReader br = new BufferedReader(new FileReader(files[number]));
				row = br.readLine();
				this.size=Integer.parseInt(row);
				this.field= new float[this.size][this.size];
				this.ground= new float[this.size][this.size];
				row = br.readLine();
				help2=new String[Integer.parseInt(row)][2];
				row = br.readLine();

				help=row.split(";");
				for(int i=0;i<help.length;i++){
					help2[i]=help[i].split(",");
				}
				for(int i=0;i<help2.length;i++){
					for(int j=0;j<help2[i].length;j++){
						this.player[i+1][j]=Integer.parseInt(help2[i][j]);
					}
				}


				for(int i =0;i<this.size;i++){
					row=br.readLine();
					help=row.split(",");
					for(int j=0;j<this.size;j++){
						this.field[j][i]=Integer.parseInt(help[j]);
					}
				}

				br.readLine();

				for(int i =0;i<this.size;i++){
					row=br.readLine();
					help=row.split(",");
					for(int j=0;j<this.size;j++){
						this.ground[j][i]=Integer.parseInt(help[j]);
					}
				}


			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			this.work=true;
			this.load=false;

		}



		if((xpos>40 && xpos<75) && (ypos<Main.sizey-230 && ypos>Main.sizey-245) && in.isMousePressed(0) && work){
			//auf save-menu
			this.create=false;
			this.load=false;
			this.save=true;
			this.name="";
		}

		if((xpos>game.Main.sizex/2-30 && xpos<game.Main.sizex/2+5) && (ypos<Main.sizey-230 && ypos>Main.sizey-245) && in.isMousePressed(0) && work){
			//save button zum wirklichen speichern
			if(this.name.length()<=0){
				this.lessChars=true;
			}
			else{

				this.name="maps/"+this.name+".txt";
				BufferedWriter bufferedWriter = null;

				try {

					//Construct the BufferedWriter object
					bufferedWriter = new BufferedWriter(new FileWriter(this.name));

					//Start writing to the output stream
					bufferedWriter.write(this.size+"");
					bufferedWriter.newLine();

					int counter=0;
					for(int i =1; i<this.player.length;i++){
						if(this.player[i][0]>=0 && this.player[i][1]>=0){
							counter++;
						}
					}
					bufferedWriter.write(counter+"");
					bufferedWriter.newLine();

					for(int i =1; i<this.player.length;i++){
						if(this.player[i][0]>=0 && this.player[i][1]>=0){
							bufferedWriter.write((int)this.player[i][0]+","+(int)this.player[i][1]+";");
						}
					}
					bufferedWriter.newLine();

					for(int i =0; i<this.field.length;i++){
						for(int j =0; j<this.field.length;j++){

							bufferedWriter.write((int)this.field[j][i]+",");

						}
						bufferedWriter.newLine();
					}
					bufferedWriter.newLine();

					for(int i =0; i<this.ground.length;i++){
						for(int j =0; j<this.ground.length;j++){

							bufferedWriter.write((int)this.ground[j][i]+",");

						}
						bufferedWriter.newLine();
					}


				} catch (Exception ex) {
					ex.printStackTrace();
				}finally {
					//Close the BufferedWriter
					try {
						if (bufferedWriter != null) {
							bufferedWriter.flush();
							bufferedWriter.close();
						}
					} catch (IOException ex) {
						ex.printStackTrace();
					}
				}

				this.lessChars=false;
				this.save=false;
			}
		}


		if((xpos>game.Main.sizex/2 && xpos<game.Main.sizex/2+45) && (ypos<Main.sizey-170 && ypos>Main.sizey-185) && in.isMouseButtonDown(0)&& this.create){
			//auf small
			this.size=15;
		}
		if((xpos>game.Main.sizex/2 && xpos<game.Main.sizex/2+55) && (ypos<Main.sizey-200 && ypos>Main.sizey-215) && in.isMouseButtonDown(0)&& this.create){
			//auf medium
			this.size=19;
		}
		if((xpos>game.Main.sizex/2 && xpos<game.Main.sizex/2+30) && (ypos<Main.sizey-230 && ypos>Main.sizey-245) && in.isMouseButtonDown(0)&& this.create){
			//auf big
			this.size=21;
		}
		if((xpos>game.Main.sizex/2 && xpos<game.Main.sizex/2+55) && (ypos<Main.sizey-280 && ypos>Main.sizey-295) && in.isMousePressed(0) && this.sizefield>0 && this.create){
			//auf create
			this.create=false;

			this.field = new float[this.size][this.size];
			this.ground = new float[this.size][this.size];

			for(int i=0;i<this.size;i++){
				for(int j=0;j<this.size;j++){
					this.ground[i][j]=0;
					this.field[i][j]=1;

				}

			}
			timer= new Timer();
			timer.schedule(new TimerTask() {
				public void run() {
					work=true;
					timer.cancel();
					timer.purge();
				};
			}, 300);

		}


		if((xpos>40 && xpos<95) && (ypos<Main.sizey-275 && ypos>Main.sizey-290) && in.isMouseButtonDown(0)){
			//auf ground
			this.mod="ground";
			this.selected=0;

		}
		if((xpos>40 && xpos<165) && (ypos<Main.sizey-305 && ypos>Main.sizey-320) && in.isMouseButtonDown(0)){
			//auf Indestructible
			this.mod="indes";
			this.selected=0;

		}
		if((xpos>40 && xpos<95) && (ypos<Main.sizey-335 && ypos>Main.sizey-350) && in.isMouseButtonDown(0)){
			//auf fields
			this.mod="field";
			this.selected=1;

		}
		if((xpos>40 && xpos<175) && (ypos<Main.sizey-365 && ypos>Main.sizey-380) && in.isMouseButtonDown(0)){
			//auf starts
			this.mod="starts";
			this.selected=0;

		}

		if((xpos>30 && xpos<235) && (ypos<Main.sizey-405 && ypos>Main.sizey-685) && in.isMouseButtonDown(0)){
			//in dem auswahlkasten
			int help = (xpos-30)/30+7*(int)((Main.sizey-ypos-405)/30);

			if(this.mod.equals("ground") && help<this.grounds.length){
				this.selected=help;
			}
			else if(this.mod.equals("field") && help<this.fields.length){
				this.selected=help+1;
			}
			else if(this.mod.equals("starts") && help<this.fields.length){
				this.selected=help;
			}

		}

		if((xpos>this.startx && xpos<this.startx+this.sizefield) && (ypos<Main.sizey-this.starty && ypos>Main.sizey-this.starty-this.sizefield) && in.isMouseButtonDown(0) && work){
			//in dem feld
			int x=Math.round((xpos-this.startx)/30);
			int y=Math.round((Main.sizey-ypos-this.starty)/30);

			if(this.mod.equals("field")){
				field[x][y]=this.selected;
			}

			if(this.mod.equals("ground")){
				ground[x][y]=this.selected;
			}

			if(this.mod.equals("indes")){
				field[x][y]=this.selected;
			}
			if(this.mod.equals("starts")){
				if(this.selected==0){
					for(int i=1;i<this.player.length;i++){
						if(this.player[i][0]==x && this.player[i][1]==y){
							this.player[i]=new float[]{-1, -1};
						}
					}
				}
				else{
					player[this.selected]=new float[]{x,y};
					field[x][y]=1;
					if((y+1)<this.size){field[x][y+1]=1;}
					if((y-1)>=0){field[x][y-1]=1;}
					if((x+1)<this.size){field[x+1][y]=1;}
					if((x-1)>=0){field[x-1][y]=1;}
				}
			}

		}


		this.sizefield=30*this.size;
		this.startx=(Main.sizex-280-this.sizefield)/2+280;
		this.starty=(Main.sizey-this.sizefield)/2;
		this.minix=(280-this.size*7)/2;
		this.miniy=(165-this.size*7)/2;



		if(this.save==true){
			in.addKeyListener(this);
			if(in.isKeyPressed(Input.KEY_BACK) && this.name.length()>1){

				int cut=this.name.length()-1;
				this.name=this.name.substring(0, cut-1);
			}
		}



	}

	/**
	 * Returns the id of this state
	 */
	public int getID() {
		// TODO Auto-generated method stub
		return 8;
	}

}

